
#include "Input.h"

#include "../Settings.h"

Input& Input::instance(){
    static Input input;
    return input;
}

Input::Input(){
    screen_height = 
        Settings::instance().getFloatValue("graphics","screen_height");
    screen_width = 
        Settings::instance().getFloatValue("graphics","screen_width");
}

Input::~Input(){
}

void Input::updateKey(SDLKey key, bool down){
    if(down){
        std::set<SDLKey>::iterator it = down_keys.find(key);
        if (it == down_keys.end()) {
            down_keys.insert(key);
        }
    } else {
        std::set<SDLKey>::iterator it = down_keys.find(key);
        if(it != down_keys.end()){
            down_keys.erase(it);
        }
    }
}

void Input::updateMouseButton(int b, bool down) {
//    std::cerr << "updating mouse button " << b << " val " << down << std::endl;
    if (down) {
        std::set<int>::iterator it = down_buttons.find(b);
        if (it == down_buttons.end()) {
            down_buttons.insert(b);
        }
    } else {
        std::set<int>::iterator it = down_buttons.find(b);
        if(it != down_buttons.end()){
            down_buttons.erase(it);
        }
    }
}

bool Input::any(std::vector<Checker*>* checks, bool clear) {
    std::vector<Checker*>::iterator it = checks->begin();
    bool yes = false;
    for (; it != checks->end(); ++it) {
        if ((*it)->check()) {
            yes = true;
            if (clear)
                (*it)->clear();
        }
    }
    return yes;
}

bool Input::isKeyDown(const std::string key) {
    std::map<std::string, std::vector<Checker*>*>::const_iterator it = key_bindings.find(key);
    if(it == key_bindings.end()){ return false; }
//    std::vector<Checker*>* checkers = it->second;
    return any(it->second);
//    return (it->second)->check();
}

bool Input::isKeyDown(SDLKey key) const {
    std::set<SDLKey>::const_iterator it = down_keys.find(key);
    return it != down_keys.end();
}

bool Input::isKeyDownAndClear(const std::string key) {
    std::map<std::string, std::vector<Checker*>*>::const_iterator it = key_bindings.find(key);
    if (it == key_bindings.end()) { return false; }
    return any(it->second, true);
    //bool ret = (it->second)->check();
    //(it->second)->clear();
    //return ret;
}

bool Input::isButtonDown(int b) const {
    std::set<int>::const_iterator it = down_buttons.find(b);
    return it != down_buttons.end();
}

bool Input::registerBinding(const std::string task, const std::string key) {
    if (isMouseKey(key)) {
        addBinding(task, new MouseChecker(key));
        //key_bindings[task] = new MouseChecker(key);
    } else {
        addBinding(task, new KeyChecker(key));
        //key_bindings[task] = new KeyChecker(key);
    }
    return true;
}

void Input::addBinding(const std::string task, Checker* checker) {
    std::map<std::string, std::vector<Checker*>*>::iterator it;
    it = key_bindings.find(task);
    if (it == key_bindings.end()) {
        key_bindings[task] = new std::vector<Checker*>();
    }
    key_bindings[task]->push_back(checker);
}

bool Input::registerBindings(std::map<std::string, std::string> mapping) {
    std::map<std::string, std::string>::iterator it = mapping.begin();
    for (; it != mapping.end(); ++it) {
        registerBinding(it->first, it->second);
    }
    return true;
}


std::vector<SDLKey> Input::getAllDownKeys(void) const {
    std::set<SDLKey>::const_iterator it = down_keys.begin();
    std::vector<SDLKey> result;

    while(it != down_keys.end()){
        result.push_back(*it);
        ++it;
    }

    return result;
}

bool Input::isMouseKey(const std::string str) {
    if (str == "<mouse_left>")
        return true;
    if (str == "<mouse_right>")
        return true;
    if (str == "<scroll_up>")
        return true;
    if (str == "<scroll_down>")
        return true;
    return false;
}

Vector2D Input::getMousePosition(bool ortho) const {
    int x = 0, y = 0;
    float x_coord, y_coord;
    SDL_GetMouseState(&x, &y);
    if (ortho) {
        x_coord = (1.0f *x) / screen_width;
        y_coord = 0.75f - ((1.0f *y) / screen_height * 0.75f);
    } else {
        x_coord = (float)x;
        y_coord = (float)y;
    }
    return Vector2D(x_coord, y_coord);
}

